package cn.arikeky.basic.service.impl;

import cn.arikeky.basic.config.BussinessException;
import cn.arikeky.basic.constant.BaseConstant;
import cn.arikeky.basic.dto.EmailDto;
import cn.arikeky.basic.service.IVerifyCodeService;
import cn.arikeky.basic.util.StrUtils;
import cn.arikeky.basic.util.VerifyCodeUtils;
import cn.arikeky.basic.dto.RegisterDto;
import cn.arikeky.user.domain.User;
import cn.arikeky.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JavaMailSender javaMailSender;


    @Override
    public String graph(String key) {
        // 判断是否为空，手动抛出异常
        if (StringUtils.isEmpty(key)){
            throw new BussinessException("参数不能为空");
        }
        // 调用工具类随机生成字符串
        String code = StrUtils.getComplexRandomString(1);
        //存入到redis
        redisTemplate.opsForValue().set(key,code);
        // 生成图形验证码返回给前端
        return VerifyCodeUtils.VerifyCode(100,35,code);
    }

    @Override
    public void smsCode(RegisterDto vo) {
        if ("register".equals(vo.getType())){
            // 判断接收的前端参数非空
            imgageCode(vo);
            // 短信验证码
            verifyImageCode(String.format(BaseConstant.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX, vo.getPhone()));
        } else if ("binder".equals(vo.getType())){
            verifyImageCode(String.format(BaseConstant.VerifyCodeConstant.BINDER_REGISTER_PREFIX, vo.getPhone()));
        }
    }

    private void imgageCode(RegisterDto vo) {
        if (StringUtils.isBlank(vo.getPhone()) || StringUtils.isBlank(vo.getImageCodeValue()) || StringUtils.isBlank(vo.getImageCodeKey())){
            throw new BussinessException("参数错误，请传入正确的参数");
        }
        // 校验redis中的图形验证码是否正确
        // 根据图形验证码的key值获取redis中图形验证码的code
        String imageCodeTmp = (String)redisTemplate.opsForValue().get(vo.getImageCodeKey());
        if (imageCodeTmp == null){
            throw new BussinessException("请输入验证码！");
        }
        if (!imageCodeTmp.toString().equalsIgnoreCase(vo.getImageCodeValue())){
            throw new BussinessException("验证码错误请重新填写验证码！");
        }
        // 判断手机号是否已经注册
        // 根据电话查询用户
        User user = userMapper.findPhoneById(vo.getPhone());
        if (user != null){
            throw new BussinessException("该手机号已被注册");
        }
    }

    private String verifyImageCode(String RedisKey) {

        // 试用业务键拼接手机号

        String smsCodeValueTmp = (String)redisTemplate.opsForValue().get(RedisKey);
        // 判断非空 为空生成新的验证码
        String smsCode = "";
        if (smsCodeValueTmp == null){
            smsCode = StrUtils.getRandomString(6);
        } else {
            // 验证码一分钟延迟
            // code:时间戳
            String[] smsCodeValueArray = smsCodeValueTmp.toString().split(":");
            // 获取老的时间戳
            Long oldTimeTmp = Long.valueOf(smsCodeValueArray[1]);
            // 获取现在的时间戳
            long nowTimeTmp = System.currentTimeMillis();
            // 判断时间有没有超过一分钟
            if (nowTimeTmp - oldTimeTmp <= 1*60*1000){
                throw new BussinessException("请一分钟后重试");
            }
            // 如果redis中还存在验证码，并且超过了一分钟，那么使用之前的验证码并重置时间即可
            smsCode = smsCodeValueArray[0];
        }
        // 设置手机验证码到Redis中，不管是否是第一次获取手机验证码都直接设置到Redis中并设置过期时间为三分钟
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(RedisKey, smsCodeValue,3, TimeUnit.MINUTES);
        // 发送短信
//        SmsUtil.send(phone, "尊敬的用户您好！本次登录的验证码为：" + smsCode + "/r【验证码三分钟内有效】");
        log.info("验证码为：{}",smsCode);
        return smsCode;
    }

    @Override
    public void emailCode(EmailDto dto) {
        // 判断非空
        // 获取参数
        String email = dto.getEmail();
        String emailCodeKey = dto.getEmailCodeKey();
        String emailCodeValue = dto.getEmailCodeValue();
//        System.out.println(email+emailCodeKey+emailCodeValue);
        // 获取验证码
        String smsCode = VerifyGetEmail(dto, email, emailCodeKey, emailCodeValue);

        // 发送邮件
        sendMail(email, smsCode);
    }

    private void sendMail(String email, String smsCode) {
        // 创建复杂邮件对象
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        // 发送复杂邮件的工具类
        MimeMessageHelper helper = null;
        try {
            helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
            helper.setFrom("864753517@qq.com");
            helper.setSubject("宠物之家");
            // 设置文本内容，第二个参数 true 代表是否是一个html内容
            helper.setText("您本次注册的验证码为："+ smsCode +"五分钟内有效！",true);
            // 添加附件
//            helper.addAttachment("好东西.jpg",new File("D:\\资料\\学习资料\\4.jpg"));
            // 设置收件人
            helper.setTo(email);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BussinessException("发送邮件失败");
        }
        // 发送邮件
        javaMailSender.send(mimeMessage);

        System.out.println("验证码为：" + smsCode);
    }

    private String VerifyGetEmail(EmailDto dto, String email, String emailCodeKey, String emailCodeValue) {
        // 判断邮箱是否已经注册
        // 根据邮箱查询用户
        User user = userMapper.findEmailById(email);
        if (user != null){
            throw new BussinessException("该邮箱已被注册");
        }
        // 校验redis中的图形验证码是否正确
        // 根据图形验证码的key值获取redis中图形验证码的code
        Object imageCodeTmp = redisTemplate.opsForValue().get(emailCodeKey);
        if (imageCodeTmp == null){
            throw new BussinessException("请输入验证码！");
        }
        if (!imageCodeTmp.toString().equalsIgnoreCase(emailCodeValue)){
            throw new BussinessException("验证码错误请重新填写验证码！");
        }
        // 用于拼接邮件的业务键
        String emailCode = BaseConstant.VerifyCodeConstant.EMAIL_REGISTER_PREFIX + dto.getEmail();
        // 判断非空 为空生成新的验证码
        String CodeValueTmp = (String) redisTemplate.opsForValue().get(emailCode);
        String smsCode = "";
        smsCode = StrUtils.getRandomString(6);
        if (CodeValueTmp == null){
            smsCode = StrUtils.getRandomString(6);
        } else {
            // 验证码一分钟延迟
            // code:时间戳
            String[] smsCodeValueArray = CodeValueTmp.split(":");
            // 获取老的时间戳
            Long oldTimeTmp = Long.valueOf(smsCodeValueArray[1]);
            // 获取现在的时间戳
            long nowTimeTmp = System.currentTimeMillis();
            // 判断时间有没有超过一分钟
            if (nowTimeTmp - oldTimeTmp <= 1*60*1000){
                throw new BussinessException("请一分钟后重试");
            }
            // 如果redis中还存在验证码，并且超过了一分钟，那么使用之前的验证码并重置时间即可
            smsCode = smsCodeValueArray[0];
        }
        // 设置过期时间为五分钟
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(emailCode, smsCodeValue,5, TimeUnit.MINUTES);
        return smsCode;
    }
}
